package com.hnhcyy.goods.service.impl;

import ch.qos.logback.core.net.SyslogOutputStream;
import com.alibaba.fastjson.JSON;
import com.hnhcyy.goods.mapper.SpMchkMapper;
import com.hnhcyy.goods.mapper.SpOldMchkMapper;
import com.hnhcyy.goods.pojo.*;
import com.hnhcyy.goods.service.EsGoodsService;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author sheyongjun
 * @Date 2019/4/12 下午 3:04
 **/
@Service
public class EsGoodsServiceImpl implements EsGoodsService {

    @Value("${eshop.goods.index}")
    private String INDEX_GOODS;
    @Value("${eshop.spMchk.index}")
    private String INDEX_SPMCHK;
    @Value("${eshop.spOldMchk.index}")
    private String INDEX_SPOLDMCHK;
    @Value("${eshop.goods.type}")
    private String TYPE_GOODS;
    @Value("${eshop.spMchk.type}")
    private String TYPE_SPMCHK;
    @Value("${eshop.spOldMchk.type}")
    private String TYPE_SPOLDMCHK;
    @Value("${eshop.goods.source_field}")
    private String source_field;

    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Autowired
    private SpMchkMapper spMchkMapper;
    @Autowired
    private SpOldMchkMapper spOldMchkMapper;

    /*private XContentBuilder createIKMapping(String indexType) {
        XContentBuilder mapping = null;
        try {
            mapping = XContentFactory.jsonBuilder().startObject()
                    // 索引库名（类似数据库中的表）
                    .startObject(indexType).startObject("properties")
                    .startObject("spmch").field("type", "string")
                    .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                    .startObject("shpchd").field("type", "string")
                    .field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
                    //.field("boost",100).endObject()
                    // 姓名
                    //.startObject("name").field("type", "string").endObject()
                    // 位置
                    //.startObject("location").field("type", "geo_point").endObject()
                    //.endObject().startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject().endObject().endObject();
                    .endObject().endObject().endObject();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mapping;
    }*/

    /**
     * 创建索引(添加)
     *
     * @return
     * @throws IOException
     */
    public RestHighLevelClient createIndexForIk(RestHighLevelClient client, String index, String type) throws IOException {
        CreateIndexRequest request = new CreateIndexRequest(index);
        request.settings(Settings.builder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 1))
                // 设置mapping
                .mapping(type, "spmch",
                        "type=text,analyzer=ik_max_word","shpchd","type=text,analyzer=ik_max_word")
                // 创建超时
                .timeout(TimeValue.timeValueMinutes(2))
                // 连接到主节点超时时间
                .masterNodeTimeout(TimeValue.timeValueMinutes(1));
        CreateIndexResponse indexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        boolean acknowledged = indexResponse.isAcknowledged();
        boolean shardsAcknowledged = indexResponse.isShardsAcknowledged();
        System.out.println(acknowledged + "," + shardsAcknowledged);
        return client;
    }

    @Override
    public String saveGoods(Goods goods)  {
        Map<String, Object> data =  addData(goods);
        // 商品ID和商家ID组成ID
        String id = goods.getSpid() + "-" + goods.getGoodsExtend().getSjid();
        IndexRequest indexRequest = new IndexRequest(INDEX_GOODS, TYPE_GOODS, id).source(data);
        try {
            IndexResponse response = createIndexForIk(this.restHighLevelClient, INDEX_GOODS, TYPE_GOODS)
                    .index(indexRequest, RequestOptions.DEFAULT);
            System.out.println("id -> " + response.getId());
            System.out.println("version -> " + response.getVersion());
            System.out.println("result -> " + response.getResult());
            return JSON.toJSONString(response);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String bulkSaveGoods(List<Goods> goodsList) {
        BulkRequest bulkRequest = new BulkRequest();
        goodsList.parallelStream().forEach(goods -> {
            Map<String, Object> data = addData(goods);
            // 商品ID和商家ID组成ID
            String id = goods.getSpid() + "-" + goods.getGoodsExtend().getSjid();
            IndexRequest indexRequest = new IndexRequest(INDEX_GOODS, TYPE_GOODS, id).source(data);
            bulkRequest.add(indexRequest);
        });
        try {
            BulkResponse bulk = createIndexForIk(this.restHighLevelClient, INDEX_GOODS, TYPE_GOODS)
                    .bulk(bulkRequest, RequestOptions.DEFAULT);
            return JSON.toJSONString(bulk);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }

    @Override
    public String bulkSaveSpMchk(List<SpMchk> spMchkList) {
        BulkRequest bulkRequest = new BulkRequest();
        if(spMchkList == null){
            spMchkList = spMchkMapper.selectListAll();
            try {
                restHighLevelClient = createIndexForIk(this.restHighLevelClient, INDEX_SPMCHK, TYPE_SPMCHK);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        spMchkList.parallelStream().forEach(spMchk -> {
            Goods goods = spMchk.getGoods();
            Map<String, Object> data = new HashMap<>();
            data.put("spid", spMchk.getSpid());
            data.put("spmch", goods.getSpmch());
            data.put("zjm", goods.getZjm());
            data.put("shpchd", goods.getShpchd());
            data.put("price", goods.getPrice());
            data.put("lingshoujia", goods.getLingshoujia());
            data.put("dwbh", spMchk.getDwbh());
            data.put("fenable", spMchk.getFenable());
            // 商品ID和单位ID组成ID
            String id = spMchk.getSpid() + "-" + spMchk.getDwbh();
            IndexRequest indexRequest = new IndexRequest(INDEX_SPMCHK, TYPE_SPMCHK, id).source(data);
            bulkRequest.add(indexRequest);
        });
        try {
            BulkResponse bulk = this.restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            return JSON.toJSONString(bulk);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String bulkSaveSpOldMchk(List<SpOldMchk> spOldMchkList) {
        BulkRequest bulkRequest = new BulkRequest();
        if(spOldMchkList == null){
            spOldMchkList = spOldMchkMapper.selectListAll();
            try {
                restHighLevelClient = createIndexForIk(this.restHighLevelClient, INDEX_SPOLDMCHK, TYPE_SPOLDMCHK);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        spOldMchkList.parallelStream().forEach(spOldMchk -> {
            Goods goods = spOldMchk.getGoods();
            Map<String, Object> data = new HashMap<>();
            data.put("spid", spOldMchk.getSpid());
            data.put("spmch", goods.getSpmch());
            data.put("zjm", goods.getZjm());
            data.put("shpchd", goods.getShpchd());
            data.put("price", goods.getPrice());
            data.put("lingshoujia", goods.getLingshoujia());
            data.put("dwbh", spOldMchk.getDwbh());
            data.put("fenable", spOldMchk.getFenable());
            // 商品ID和单位ID组成ID
            String id = spOldMchk.getSpid() + "-" + spOldMchk.getDwbh();
            IndexRequest indexRequest = new IndexRequest(INDEX_SPOLDMCHK, TYPE_SPOLDMCHK, id).source(data);
            bulkRequest.add(indexRequest);
        });
        try {
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            return JSON.toJSONString(bulk);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @Description: 条件搜索商品
     * @Author: sheyongjun
     * @CreateDate: 2019/4/13 上午 11:48
     * @Version: 1.0
     */
    @Override
    public List<Goods> list(GoodsQueryParam goodsQueryParam) {
        if(goodsQueryParam.getAppointGoods()){
            // 老客户指定的商品
            spOldMchkList(goodsQueryParam);
        }
        List<Goods> goodsList = goodsList(goodsQueryParam);
        Map<String, List<Goods>> goodsListMap = spMchkList(goodsQueryParam);
        // 加入可销的商品
        if (goodsListMap != null && goodsListMap.get("goodsListEnable") != null) {
            goodsList.addAll(goodsListMap.get("goodsListEnable"));
        }
        // 移除禁销的商品
        if (goodsListMap != null && goodsListMap.get("goodsListUnable") != null) {
            goodsList.removeAll(goodsListMap.get("goodsListUnable"));
//            goodsList.stream().distinct();
        }
        return goodsList;
    }


    /**
     * @Description:    老客户表
     * @Author:         sheyongjun
     * @CreateDate:     2019/4/17 下午 3:09
     * @Version:        1.0
     */
    private List<Goods> spOldMchkList(GoodsQueryParam goodsQueryParam){
        if (StringUtils.isBlank(goodsQueryParam.getDwbh())) {
            return null;
        }
        // 创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(INDEX_SPOLDMCHK);
        // 设置搜索类型
        searchRequest.types(TYPE_SPOLDMCHK);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 分页
        if (goodsQueryParam.getOffset() != null) {
            searchSourceBuilder.from(goodsQueryParam.getOffset());
        }
        if (goodsQueryParam.getSize() != null) {
            searchSourceBuilder.size(goodsQueryParam.getSize());
        }
        BoolQueryBuilder boolQueryBuilder = commonBoolQueryBuilder(goodsQueryParam);

        boolQueryBuilder.must(QueryBuilders.termQuery("dwbh", goodsQueryParam.getDwbh()));

        // 设置boolQueryBuilder到searchSourceBuilder
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        List<Goods> goodsList = new ArrayList<>();
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 获取响应结果
            SearchHits hits = searchResponse.getHits();
            // 匹配的总记录数
            long totalHits = hits.totalHits;
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                Goods goods = new Goods();
                //源文档
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                goods.setSpid((String) sourceAsMap.get("spid"));
                goods.setSpmch((String) sourceAsMap.get("spmch"));
                goods.setShpchd((String) sourceAsMap.get("shpchd"));
                goods.setPrice((Double) sourceAsMap.get("price"));
                goods.setLingshoujia((Double) sourceAsMap.get("lingshoujia"));
                goodsList.add(goods);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return goodsList;
    }

    /**
     * @Description:    共用BoolQuery
     * @Author:         sheyongjun
     * @CreateDate:     2019/4/17 下午 3:26
     * @Version:        1.0
     */
    private BoolQueryBuilder commonBoolQueryBuilder(GoodsQueryParam goodsQueryParam) {
        // 创建布尔查询对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 搜索条件
        // 根据关键字搜索
        if (StringUtils.isNotBlank(goodsQueryParam.getSearch())) {
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(goodsQueryParam.getSearch(),
                    "spmch", "spid", "shpchd");
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }
        // 过滤商品类别
        if (goodsQueryParam.getFlbid() != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("flbid", goodsQueryParam.getFlbid()));
        }
        return boolQueryBuilder;
    }

    /**
     * @Description: 商品客户加减表
     * @Author: sheyongjun
     * @CreateDate: 2019/4/13 上午 10:59
     * @Version: 1.0
     */
    private Map<String, List<Goods>> spMchkList(GoodsQueryParam goodsQueryParam) {
        if (StringUtils.isBlank(goodsQueryParam.getDwbh())) {
            return null;
        }
        // 创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(INDEX_SPMCHK);
        // 设置搜索类型
        searchRequest.types(TYPE_SPMCHK);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 分页
        if (goodsQueryParam.getOffset() != null) {
            searchSourceBuilder.from(goodsQueryParam.getOffset());
        }
        if (goodsQueryParam.getSize() != null) {
            searchSourceBuilder.size(goodsQueryParam.getSize());
        }
        // 创建布尔查询对象
        BoolQueryBuilder boolQueryBuilder = commonBoolQueryBuilder(goodsQueryParam);

        boolQueryBuilder.must(QueryBuilders.termQuery("dwbh", goodsQueryParam.getDwbh()));

        // 设置boolQueryBuilder到searchSourceBuilder
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        // 执行搜索
        SearchResponse searchResponse = null;
        List<Goods> goodsListEnable = new ArrayList<>(); // 可以销售的商品
        List<Goods> goodsListUnable = new ArrayList<>(); // 禁销的商品
        try {
//            searchResponse = restHighLevelClient.search(searchRequest);
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 获取响应结果
            SearchHits hits = searchResponse.getHits();
            // 匹配的总记录数
            long totalHits = hits.totalHits;
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                Goods goods = new Goods();
                //源文档
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                goods.setSpid((String) sourceAsMap.get("spid"));
                goods.setSpmch((String) sourceAsMap.get("spmch"));
                goods.setShpchd((String) sourceAsMap.get("shpchd"));
                goods.setPrice((Double) sourceAsMap.get("price"));
                goods.setLingshoujia((Double) sourceAsMap.get("lingshoujia"));
                boolean fenable = (Boolean) sourceAsMap.get("fenable");
                if (fenable) {
                    goodsListEnable.add(goods);
                } else {
                    goodsListUnable.add(goods);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        Map<String, List<Goods>> mapGoodsList = new HashMap<>(2);
        mapGoodsList.put("goodsListEnable", goodsListEnable);
        mapGoodsList.put("goodsListUnable", goodsListUnable);
        return mapGoodsList;
    }

    /**
     * @Description: 商品表
     * @Author: sheyongjun
     * @CreateDate: 2019/4/12 下午 3:07
     * @Version: 1.0
     */
    private List<Goods> goodsList(GoodsQueryParam goodsQueryParam) {
        // 创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(INDEX_GOODS);
        // 设置搜索类型
        searchRequest.types(TYPE_GOODS);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 分页
        if (goodsQueryParam.getOffset() != null) {
            searchSourceBuilder.from(goodsQueryParam.getOffset());
        }
        if (goodsQueryParam.getSize() != null) {
            searchSourceBuilder.size(goodsQueryParam.getSize());
        }
        // 过虑源字段
//        String[] source_field_array = source_field.split(",");
//        searchSourceBuilder.fetchSource(source_field_array, new String[]{});
        // 创建布尔查询对象
        BoolQueryBuilder boolQueryBuilder = commonBoolQueryBuilder(goodsQueryParam);
        // 商家ID
        if (goodsQueryParam.getSjid() != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("sjid", goodsQueryParam.getSjid()));
        }
        // 设置boolQueryBuilder到searchSourceBuilder
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        // 执行搜索
        List<Goods> goodsList = new ArrayList<>();
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 获取响应结果
            SearchHits hits = searchResponse.getHits();
            // 匹配的总记录数
            long totalHits = hits.totalHits;
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                Goods goods = new Goods();
                //源文档
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                goods.setSpid((String) sourceAsMap.get("spid"));
                goods.setSpmch((String) sourceAsMap.get("spmch"));
                goods.setShpchd((String) sourceAsMap.get("shpchd"));
                goods.setPrice((Double) sourceAsMap.get("price"));
                goods.setLingshoujia((Double) sourceAsMap.get("lingshoujia"));
                GoodsExtend goodsExtend = new GoodsExtend();
                goodsExtend.setXsqy((String) sourceAsMap.get("xsqy"));
                goodsExtend.setSjid((Integer) sourceAsMap.get("sjid"));
                goods.setGoodsExtend(goodsExtend);
                goodsList.add(goods);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 省区控销过滤
        if (goodsQueryParam.getQyid() != null) {
            Integer qyid = goodsQueryParam.getQyid();
            return goodsList.stream().filter(goods ->
                 goods.getGoodsExtend().getXsqy().substring(qyid - 1, qyid).equals("1")

            ).collect(Collectors.toList());
            /*goodsList.stream().filter(goods -> {
                        if (goods.getGoodsExtend().getXsqy().substring(qyid - 1, qyid).equals("1")) {
                            System.out.println("xsqy:" + goods.getGoodsExtend().getXsqy());
                            return true;
                        }
                        return false;
                    }

            ).forEach(e-> System.out.println(e.getSpid()));*/
        }
        return goodsList;
    }

    @Override
    public boolean exists(String type, String id) {
        GetRequest getRequest = new GetRequest(INDEX_GOODS, type, id);
        // 不返回的字段
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        try {
            return this.restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public int updateGoods(String id, Goods goods) {
        UpdateRequest updateRequest = new UpdateRequest(INDEX_GOODS, TYPE_GOODS, id);
        Map<String, Object> data = addData(goods);
        updateRequest.doc(data);
        try {
            UpdateResponse response = this.restHighLevelClient.update(updateRequest,
                    RequestOptions.DEFAULT);
            return response.status().getStatus();
        } catch (IOException e) {
            e.printStackTrace();
            return 500;
        }
    }

    @Override
    public int delete(String type, String id) {
        DeleteRequest deleteRequest = new DeleteRequest(INDEX_GOODS, type, id);
        try {
            DeleteResponse  response = this.restHighLevelClient.delete(deleteRequest,
                    RequestOptions.DEFAULT);
            return response.status().getStatus();
        } catch (IOException e) {
            e.printStackTrace();
            return 500;
        }
    }

    /**
     * @Description:    把对象保存到Map
     * @Author:         sheyongjun
     * @CreateDate:     2019/4/16 上午 11:07
     * @Version:        1.0
     */
    private Map<String, Object> addData(Goods goods) {
        Map<String, Object> data = new HashMap<>();
        data.put("spid", goods.getSpid());
        data.put("spmch", goods.getSpmch());
        data.put("zjm", goods.getZjm());
        data.put("shpchd", goods.getShpchd());
        data.put("price", goods.getPrice());
        data.put("lingshoujia", goods.getLingshoujia());
        data.put("xsqy", goods.getGoodsExtend().getXsqy());
        data.put("sjid", goods.getGoodsExtend().getSjid());
        return data;
    }
}
